//----------------------------------------------------------------
//	NPythonBind Lib
//
//	class Member function bind
//	use template to generate a PyCFunction body for every member function
//
//	Author: Neil Fang
//	Date:	March,2008
//----------------------------------------------------------------
#pragma once
#include "NConversion.h"

//-- 0 arg -------------------------------------------------------------
/**
*	Bind member function no arg
*	@param N		method index
*	@param C,R,T0	R C::MethodName(T0)
*/
template<int N, typename C, typename R>
struct NMethodNoArg
{
	/**
	*	the PyCFunction body
	*/
	static PyObject* exportFunc(PyObject* self, PyObject* args)
	{
		PyObject* pRet = NULL;
		try
		{
			C* pObj= (C*)self;

			R r = (pObj->*m_func)();

			pRet = NConversion<R>::build(r);
		}
		catch(NException& e)
		{
			pRet = NULL;
			PyErr_SetString(PyExc_Exception, e.what());
		}

		return pRet;
	}

	/**
	*	member function ptr
	*/
	typedef R(C::*TFunc)();
	static TFunc m_func;
};
/**
*	static member data define
*	one class should only use once, so there no link error
*/
template<int N, typename C, typename R>
typename NMethodNoArg<N,C,R>::TFunc NMethodNoArg<N,C,R>::m_func = NULL;

/**
* helper function
*/
template<int N, typename C, typename R>
PyMethodDef makeMethodDef(R(C::*func)(), const char* szName, const char* szDoc="blank doc.")
{
	NMethodNoArg<N, C, R>::m_func = func;

	PyCFunction pyFunc = NMethodNoArg<N, C, R>::exportFunc;

	PyMethodDef def = 
	{
		szName, pyFunc, METH_NOARGS, szDoc
	};	

	return def;
}


//-- 1 arg -------------------------------------------------------------
/**
 *	Bind member function with 1 arg
 *	@param N		method index
 *	@param C,R,T0	R C::MethodName(T0)
*/
template<int N, typename C, typename R, typename T0>
struct NMethod1Arg
{
	static PyObject* exportFunc(PyObject* self, PyObject* args)
	{
		PyObject* pRet = NULL;
		try
		{
			C* pObj= (C*)self;
			T0 arg1 = NConversion<T0>::parse(0, args);

			R r = (pObj->*m_func)(arg1);
			pRet = NConversion<R>::build(r);
		}
		catch(NException& e)
		{
			pRet = NULL;
			PyErr_SetString(PyExc_Exception, e.what());
		}

		return pRet;
	}

	typedef R(C::*TFunc)(T0);
	static TFunc m_func;
};

template<int N, typename C, typename R, typename T0>
typename NMethod1Arg<N,C,R,T0>::TFunc NMethod1Arg<N,C,R,T0>::m_func = NULL;

template<int N, typename C, typename R, typename T0>
PyMethodDef makeMethodDef(R(C::*func)(T0), const char* szName, const char* szDoc="blank doc.")
{
	NMethod1Arg<N, C, R, T0>::m_func = func;

	PyCFunction pyFunc = NMethod1Arg<N, C, R, T0>::exportFunc;

	PyMethodDef def = 
	{
		szName, pyFunc, METH_VARARGS, szDoc
	};	

	return def;
}
